<template>
  <transition name="zoom-in-bottom" @after-leave="$emit('dodestroy')">
    <div
      v-show="visible"
      :style="{ width: width + 'px' }"
      class="picker-panel date-range-picker"
      :class="[{
        'has-sidebar': $slots.sidebar || shortcuts,
        'has-time': showTime
      }]">
      <div class="picker-panel__body-wrapper">
        <slot name="sidebar" class="picker-panel__sidebar"></slot>
        <div class="picker-panel__sidebar" v-if="shortcuts">
          <button
            type="button"
            class="picker-panel__shortcut"
            v-for="shortcut in shortcuts"
            @click="handleShortcutClick(shortcut)">{{shortcut.text}}</button>
        </div>
        <div class="picker-panel__body">
          <div class="date-range-picker__time-header" v-if="showTime">
            <span class="date-range-picker__editors-wrap">
              <span class="date-range-picker__time-picker-wrap">
                <input
                  style="width:150px"
                  ref="minInput"
                  :placeholder="getLocale('datePicker.startDate')"
                  class="form-control date-range-picker__editor"
                  :value="minVisibleDate"
                  @input.native="handleDateInput($event, 'min')"
                  @change.native="handleDateChange($event, 'min')" readonly>
              </span>
              <span class="date-range-picker__time-picker-wrap">
                <input
                  style="width:150px"
                  :placeholder="getLocale('datePicker.startTime')"
                  class="form-control date-range-picker__editor"
                  :value="minVisibleTime"
                  @focus="minTimePickerVisible = !minTimePickerVisible"
                  @change.native="handleTimeChange($event, 'min')" readonly>
                <time-picker
                  :picker-width="minPickerWidth"
                  ref="minTimePicker"
                  :date="minDate"
                  @pick="handleMinTimePick"
                  :visible="minTimePickerVisible">
                </time-picker>
              </span>
            </span>
            <span class="icon-arrow-right"></span>
            <span class="date-range-picker__editors-wrap is-right">
              <span class="date-range-picker__time-picker-wrap">
                <input
                  style="width:150px"
                  :placeholder="getLocale('datePicker.endDate')"
                  class="form-control date-range-picker__editor"
                  :value="maxVisibleDate"
                  :readonly="!minDate"
                  @input.native="handleDateInput($event, 'max')"
                  @change.native="handleDateChange($event, 'max')" readonly>
              </span>
              <span class="date-range-picker__time-picker-wrap">
                <input
                  ref="maxInput"
                  style="width:150px"
                  :placeholder="getLocale('datePicker.endTime')"
                  class="form-control date-range-picker__editor"
                  :value="maxVisibleTime"
                  @focus="minDate && (maxTimePickerVisible = !maxTimePickerVisible)"
                  :readonly="!minDate"
                  @change.native="handleTimeChange($event, 'max')" readonly>
                <time-picker
                  :picker-width="maxPickerWidth"
                  ref="maxTimePicker"
                  :date="maxDate"
                  @pick="handleMaxTimePick"
                  :visible="maxTimePickerVisible"></time-picker>
              </span>
            </span>
          </div>
          <div class="picker-panel__content date-range-picker__content is-left">
            <div class="date-range-picker__header">
              <button
                type="button"
                @click="prevYear"
                class="picker-panel__icon-btn icon-d-arrow-left"></button>
              <button
                type="button"
                @click="prevMonth"
                class="picker-panel__icon-btn icon-arrow-left"></button>
              <div>{{ leftLabel }}</div>
            </div>
            <date-table
              selection-mode="range"
              :date="date"
              :year="leftYear"
              :month="leftMonth"
              :min-date="minDate"
              :max-date="maxDate"
              :range-state="rangeState"
              :disabled-date="disabledDate"
              @changerange="handleChangeRange"
              :first-day-of-week="firstDayOfWeek"
              @pick="handleRangePick">
            </date-table>
          </div>
          <div class="picker-panel__content date-range-picker__content is-right">
            <div class="date-range-picker__header">
              <button
                type="button"
                @click="nextYear"
                class="picker-panel__icon-btn icon-d-arrow-right"></button>
              <button
                type="button"
                @click="nextMonth"
                class="picker-panel__icon-btn icon-arrow-right"></button>
              <div>{{ rightLabel }}</div>
            </div>
            <date-table
              selection-mode="range"
              :date="rightDate"
              :year="rightYear"
              :month="rightMonth"
              :min-date="minDate"
              :max-date="maxDate"
              :range-state="rangeState"
              :disabled-date="disabledDate"
              @changerange="handleChangeRange"
              :first-day-of-week="firstDayOfWeek"
              @pick="handleRangePick">
            </date-table>
          </div>
        </div>
      </div>
      <div class="picker-panel__footer" v-if="footerVisible">
        <a v-if="clearable"
          class="picker-panel__link-btn"
          @click="handleClear">{{ getLocale('datePicker.clear') }}</a>
        <button v-if="showTime"
          type="button"
          class="picker-panel__btn"
          @click="handleConfirm()"
          :disabled="btnDisabled">{{ getLocale('datePicker.confirm') }}</button>
      </div>
    </div>
  </transition>
</template>

<script type="text/babel">
  import {DateUtils} from '../utils'
  import LOCALES from '../../../locales'
  import TimePicker from './time.vue'
  import DateTable from '../basic/date-table.vue'

  export default {

    components: { TimePicker, DateTable },

    computed: {
      footerVisible () {
        return this.showTime || this.clearable
      },

      btnDisabled () {
        return !(this.minDate && this.maxDate && !this.selecting)
      },

      leftLabel () {
        return this.date.getFullYear() + ' ' + this.getLocale('datePicker.year') + ' ' + this.getLocale(`datePicker.months.${DateUtils.MONTHS[this.date.getMonth()]}`)
      },

      rightLabel () {
        return this.rightDate.getFullYear() + ' ' + this.getLocale('datePicker.year') + ' ' + this.getLocale(`datePicker.months.${DateUtils.MONTHS[this.rightDate.getMonth()]}`)
      },

      leftYear () {
        return this.date.getFullYear()
      },

      leftMonth () {
        return this.date.getMonth()
      },

      rightYear () {
        return this.rightDate.getFullYear()
      },

      rightMonth () {
        return this.rightDate.getMonth()
      },

      minVisibleDate () {
        return this.minDate ? DateUtils.formatDate(this.minDate) : ''
      },

      maxVisibleDate () {
        return (this.maxDate || this.minDate) ? DateUtils.formatDate(this.maxDate || this.minDate) : ''
      },

      minVisibleTime () {
        return this.minDate ? DateUtils.formatDate(this.minDate, 'HH:mm:ss') : ''
      },

      maxVisibleTime () {
        return (this.maxDate || this.minDate) ? DateUtils.formatDate(this.maxDate || this.minDate, 'HH:mm:ss') : ''
      },

      rightDate () {
        const newDate = new Date(this.date)
        const month = newDate.getMonth()
        newDate.setDate(1)

        if (month === 11) {
          newDate.setFullYear(newDate.getFullYear() + 1)
          newDate.setMonth(0)
        } else {
          newDate.setMonth(month + 1)
        }
        return newDate
      }
    },

    data () {
      return {
        popperClass: '',
        minPickerWidth: 0,
        maxPickerWidth: 0,
        date: new Date(),
        minDate: '',
        maxDate: '',
        rangeState: {
          endDate: null,
          selected: true,
          selecting: false,
          row: null,
          column: null
        },
        showTime: false,
        shortcuts: '',
        value: '',
        visible: false,
        disabledDate: '',
        firstDayOfWeek: 7,
        minTimePickerVisible: false,
        maxTimePickerVisible: false,
        width: 0,
        clearable: true
      }
    },

    watch: {
      showTime (val) {
        if (!val) return
        this.$nextTick(_ => {
          const minInputElm = this.$refs.minInput
          const maxInputElm = this.$refs.maxInput
          if (minInputElm) {
            this.minPickerWidth = minInputElm.getBoundingClientRect().width + 10
          }
          if (maxInputElm) {
            this.maxPickerWidth = maxInputElm.getBoundingClientRect().width + 10
          }
        })
      },

      minDate () {
        this.$nextTick(() => {
          if (this.maxDate && this.maxDate < this.minDate) {
            const format = 'HH:mm:ss'

            this.$refs.maxTimePicker.selectableRange = [
              [
                DateUtils.parseDate(DateUtils.formatDate(this.minDate, format), format),
                DateUtils.parseDate('23:59:59', format)
              ]
            ]
          }
        })
      },

      minTimePickerVisible (val) {
//        if (val) this.$nextTick(() => this.$refs.minTimePicker.ajustScrollTop())
      },

      maxTimePickerVisible (val) {
//        if (val) this.$nextTick(() => this.$refs.maxTimePicker.ajustScrollTop())
      },

      value (newVal) {
        if (!newVal) {
          this.minDate = null
          this.maxDate = null
        } else if (Array.isArray(newVal)) {
          this.minDate = newVal[0] ? DateUtils.toDate(newVal[0]) : null
          this.maxDate = newVal[1] ? DateUtils.toDate(newVal[1]) : null
          if (this.minDate) this.date = new Date(this.minDate)
          this.handleConfirm(true)
        }
      }
    },

    methods: {

      getLocale: LOCALES.GetLocale,

      handleClear () {
        this.minDate = null
        this.maxDate = null
        this.handleConfirm(false)
      },

      handleDateInput (event, type) {
        const value = event.target.value
        const parsedValue = DateUtils.parseDate(value, 'yyyy-MM-dd')

        if (parsedValue) {
          if (typeof this.disabledDate === 'function' &&
            this.disabledDate(new Date(parsedValue))) {
            return
          }
          const target = new Date(type === 'min' ? this.minDate : this.maxDate)
          if (target) {
            target.setFullYear(parsedValue.getFullYear())
            target.setMonth(parsedValue.getMonth(), parsedValue.getDate())
          }
        }
      },

      handleChangeRange (val) {
        this.minDate = val.minDate
        this.maxDate = val.maxDate
        this.rangeState = val.rangeState
      },

      handleDateChange (event, type) {
        const value = event.target.value
        const parsedValue = DateUtils.parseDate(value, 'yyyy-MM-dd')
        if (parsedValue) {
          const target = new Date(type === 'min' ? this.minDate : this.maxDate)
          if (target) {
            target.setFullYear(parsedValue.getFullYear())
            target.setMonth(parsedValue.getMonth(), parsedValue.getDate())
          }
          if (type === 'min') {
            if (target < this.maxDate) {
              this.minDate = new Date(target.getTime())
            }
          } else {
            if (target > this.minDate) {
              this.maxDate = new Date(target.getTime())
              if (this.minDate && this.minDate > this.maxDate) {
                this.minDate = null
              }
            }
          }
        }
      },

      handleTimeChange (event, type) {
        const value = event.target.value
        const parsedValue = DateUtils.parseDate(value, 'HH:mm:ss')
        if (parsedValue) {
          const target = new Date(type === 'min' ? this.minDate : this.maxDate)
          if (target) {
            target.setHours(parsedValue.getHours())
            target.setMinutes(parsedValue.getMinutes())
            target.setSeconds(parsedValue.getSeconds())
          }
          if (type === 'min') {
            if (target < this.maxDate) {
              this.minDate = new Date(target.getTime())
            }
          } else {
            if (target > this.minDate) {
              this.maxDate = new Date(target.getTime())
            }
          }
          this.$refs[type + 'TimePicker'].value = target
          this[type + 'TimePickerVisible'] = false
        }
      },

      handleRangePick (val, close = true) {
        if (this.maxDate === val.maxDate && this.minDate === val.minDate) {
          return
        }
        this.onPick && this.onPick(val)
        this.maxDate = val.maxDate
        this.minDate = val.minDate
        if (!close || this.showTime) return
        this.handleConfirm()
      },

      changeToToday () {
        this.date = new Date()
      },

      handleShortcutClick (shortcut) {
        if (shortcut.onClick) {
          shortcut.onClick(this)
        }
      },

      resetView () {
        this.minTimePickerVisible = false
        this.maxTimePickerVisible = false
      },

      setTime (date, value) {
        let oldDate = new Date(date.getTime())
        let hour = value.getHours()
        let minute = value.getMinutes()
        let second = value.getSeconds()
        oldDate.setHours(hour)
        oldDate.setMinutes(minute)
        oldDate.setSeconds(second)
        return new Date(oldDate.getTime())
      },

      handleMinTimePick (value, visible, first) {
        this.minDate = this.minDate || new Date()
        if (value) {
          this.minDate = this.setTime(this.minDate, value)
        }

        if (!first) {
          this.minTimePickerVisible = visible
        }
      },

      handleMaxTimePick (value, visible, first) {
        if (!this.maxDate) {
          const now = new Date()
          if (now >= this.minDate) {
            this.maxDate = new Date()
          }
        }

        if (this.maxDate && value) {
          this.maxDate = this.setTime(this.maxDate, value)
        }

        if (!first) {
          this.maxTimePickerVisible = visible
        }
      },

      prevMonth () {
        this.date = DateUtils.prevMonth(this.date)
      },

      nextMonth () {
        this.date = DateUtils.nextMonth(this.date)
      },

      nextYear () {
        const date = this.date
        date.setFullYear(date.getFullYear() + 1)
        this.resetDate()
      },

      prevYear () {
        const date = this.date
        date.setFullYear(date.getFullYear() - 1)
        this.resetDate()
      },

      handleConfirm (visible = false) {
        this.$emit('pick', [this.minDate, this.maxDate], visible)
      },

      resetDate () {
        this.date = new Date(this.date)
      }
    }
  }
</script>

<style lang="scss">
  @import "../css/variables";
  @import "panel";
  @import "button";
  .date-range-picker {
    min-width: 520px;

    &.has-sidebar.has-time {
      min-width: 766px;
    }

    &.has-sidebar {
      min-width: 620px;
    }

    &.has-time {
      min-width: 660px;
    }

    table {
      table-layout: fixed;
      width: 100%;
    }

    .picker-panel__body {
      min-width: 513px;
    }

    .picker-panel__content {
      margin: 0;
    }

    .date-range-picker__header {
      position: relative;
      text-align: center;
      height: 28px;

      button {
        float: left;
      }

      div {
        font-size: 14px;
        margin-right: 50px;
      }
    }

    .date-range-picker__content {
      float: left;
      width: 50%;
      box-sizing: border-box;
      margin: 0;
      padding: 16px;

      &.is-left {
        border-right: 1px solid $datePicker-inner-border-color;
      }

      &.is-right {
        .date-range-picker__header {
          button {
            float: right;
          }

          div {
            margin-left: 50px;
            margin-right: 50px;
          }
        }
      }
    }

    .date-range-picker__editors-wrap {
      box-sizing: border-box;
      display: table-cell;

      &.is-right {
        text-align: right;
      }
    }

    .date-range-picker__time-header {
      position: relative;
      border-bottom: 1px solid $datePicker-inner-border-color;
      font-size: 12px;
      padding: 8px 5px 5px 5px;
      display: table;
      width: 100%;
      box-sizing: border-box;

      > .icon-arrow-right {
        /*font-family: FontAwesome;*/
        font-size: 20px;
        vertical-align: middle;
        display: table-cell;
        color: $datePicker-icon-color;
      }
    }

    .date-range-picker__time-picker-wrap {
      position: relative;
      display: table-cell;
      padding: 0 5px;

      .picker-panel {
        position: absolute;
        top: 13px;
        right: 0;
        z-index: 1;
        background: #fff;
      }
    }
  }
</style>
